<?php
namespace App\Repositories;

use App\Models\Group;
use App\Models\User;
use App\Models\GroupUser;
use Illuminate\Database\Eloquent\Builder;

class GroupRepository
{
    const JOINTYPE_CLOSE = 0;
    const JOINTYPE_PUBLIC = 1;
    const JOINTYPE_PASSWORD = 2;

    const CREATE_QUIZTYPE_PUBLIC = 1;
    const CREATE_QUIZTYPE_PRIVATE = 0;

    const GROUP_USER_STATUS_NOT_JOINED = 0;
    const GROUP_USER_STATUS_JOINED = 1;
    const GROUP_USER_STATUS_UNAVAILABLE = 2;

    public static $joinTypes = [
        self::JOINTYPE_CLOSE => 'close',
        self::JOINTYPE_PUBLIC => 'public',
        self::JOINTYPE_PASSWORD => 'password',
    ];

    public static $createQuizTypes = [
        self::CREATE_QUIZTYPE_PRIVATE => 'private',
        self::CREATE_QUIZTYPE_PUBLIC => 'public',
    ];


    /**
     * @param Group $group
     * @param User $user
     * @return Builder
     */
    public static function getAccountQuery(Group $group, User $user)
    {
        return GroupUser::where('group_id', $group->id)->where('user_id', $user->id);
    }

    /**
     * 系统俱乐部
     *
     * @return mixed
     */
    public static function findOfficialGroups()
    {
        return Group::where('is_official', true)->get();
    }

    /**
     * 判断俱乐部成员的状态
     *
     * @param Group $group
     * @param User $user
     * @return int
     */
    public static function getAccountStatus(Group $group, User $user)
    {
        $account = self::getAccountQuery($group, $user)
            ->withTrashed()
            ->first();

        if (!$account) {
            return self::GROUP_USER_STATUS_NOT_JOINED;
        } elseif ($account->trashed()) {
            return self::GROUP_USER_STATUS_UNAVAILABLE;
        }
        return self::GROUP_USER_STATUS_JOINED;
    }

    /**
     * 是否已经加入俱乐部
     *
     * @param Group $group
     * @param User $user
     * @return bool
     */
    public static function hasJoined(Group $group, User $user)
    {
        return self::getAccountStatus($group, $user) === self::GROUP_USER_STATUS_JOINED;
    }

    /**
     * 是否可以创建竞猜
     *
     * @param Group $group
     * @param User $user
     * @param bool $hasJoined
     * @return bool
     */
    public function canCreateQuiz(Group $group, User $user, $hasJoined = false)
    {
        if ($group->user_id == $user->id) {
            return true;
        }
        if ($group->create_quiz_type == self::CREATE_QUIZTYPE_PUBLIC
            && ($hasJoined || $this->hasJoined($group, $user))) {
            return true;
        }
        return false;
    }

    /**
     * 用户加入俱乐部
     *
     * @param Group $group
     * @param int $userId
     */
    public function addUser(Group $group, User $user)
    {
        $group->users()->attach($user->id, ['copper' => $group->copper]);
        $group->increment('users_count');
        $group->removeCache();
    }

    /**
     * 删除俱乐部用户
     *
     * @param Group $group
     * @param array $users
     */
    public function removeUser(Group $group, $users)
    {
        $affectedRows = GroupUser::where('group_id', $group->id)
            ->whereIn('user_id', $users)
            ->delete();

        if ($affectedRows) {
            $group->decrement('users_count', $affectedRows);
        }
    }

    /**
     * @param Group $group
     */
    public function addCopper(Group $group, int $copper)
    {
        GroupUser::where('group_id', $group->id)->increment('copper', $copper);
    }

    /**
     * 我的俱乐部
     *
     * @param User $user
     * @return \Illuminate\Pagination\LengthAwarePaginator
     */
    public function findGroupPaginateByUser(User $user)
    {
        return Group::join('group_user', 'groups.id', '=', 'group_user.group_id')
            ->where('group_user.user_id', $user->id)
            ->whereNull('group_user.deleted_at')
            ->where('is_display', true)
            ->orderBy('is_official', 'desc')
            ->orderBy('group_user.id', 'desc')
            ->select(['groups.*', 'group_user.copper'])
            ->paginate();
    }

    /**
     * 可以创建竞猜的俱乐部
     *
     * @param User $user
     * @return \Illuminate\Pagination\LengthAwarePaginator
     */
    public function findGroupsWhichCanCreateQuizByUser(User $user)
    {
        return Group::join('group_user', 'groups.id', '=', 'group_user.group_id')
            ->where('group_user.user_id', $user->id)
            ->where(function ($query) use ($user) {
                $query->where('groups.user_id', $user->id);
                $query->orWhere('create_quiz_type', self::CREATE_QUIZTYPE_PUBLIC);
            })
            ->select('groups.*')
            ->orderBy('group_user.updated_at', 'desc')
            ->paginate();
    }

    /**
     * @param $groupId
     * @param $userId
     * @return mixed
     */
    public function findGroupUserById($groupId, $userId)
    {
        return GroupUser::where('group_id', $groupId)
            ->where('user_id', $userId)
            ->findOrFail();
    }


    /**
     * @param $id
     * @param $copper
     * @throws \Exception
     */
    public static function decrementCopper($id, $copper)
    {
        $affectedRows = self::incrementOrDecrementCopper($id, $copper, 'decrement');
        if (!$affectedRows) {
            throw new \Exception(sprintf('insufficient copper coins {id: %s, copper: $s}', $id, $copper));
        }
    }

    /**
     * 增加铜币
     *
     * @param $id
     * @param $copper
     * @throws \Exception
     */
    public static function incrementCopper($id, $copper)
    {
        $affectedRows = self::incrementOrDecrementCopper($id, $copper);
        if (!$affectedRows) {
            throw new \Exception(sprintf('change copper coin error {id: %s, copper: $s}', $id, $copper));
        }
    }

    /**
     * @param $id
     * @param $copper
     * @param string $method
     * @return integer
     */
    public static function incrementOrDecrementCopper($id, $copper, $method = 'increment')
    {
        return GroupUser::where('id', $id)->$method('copper', $copper);
    }
}
